Scriptable Object Demo
惑星探索ゲームで、オブジェクトをクリックするとUIで
生物/植物の名前
アイコン
危険レベル
が表示されるUIのサンプルで学習していく。
Assets
https://gyazo.com/0b16d0f2d7d2035606d3e6a966e13901
CombatJane
Chomper x n
Terrain & WorldManager
https://gyazo.com/9caf60d62fefc6406da28000205cbcca
WorldManagerオブジェクトは、メッシュを持たないスクリプトを実行するだけの存在
Tree Prefab を配列で持っていて、Terrain(Mesh)のある地点に自動で生やす
UI
https://gyazo.com/98438bf99a19da7a64e660a3e0dbaef9
Canvas (uGUI)
UnityEngine.UIのusingがエラーになるときはここを見る
UI には SetPlanetInfoコンポーネントクラスがアタッチされている
code: setPlanetInfo.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class SetPlantInfo : MonoBehaviour
{
public GameObject plantInfoPanel;
public GameObject plantIcon;
public Text planeName;
public Text phreatLevel;
public void OpenPlantPanel()
{
plantInfoPanel.SetActive(true);
}
public void ClosePlantPanel()
{
plantInfoPanel.SetActive(false);
}
}
単純に、publicなプロパティをセットして
Activeにしたり消したりできるだけ。
なにげにシングルトンパターン
Scriptable Object を作る
Unityのアセットの種類を増やすようなもの
以下のようなスクリプトを作る。
code: PlantData.cs
public class PlantData : ScriptableObject
{
public enum THREAT { None, Low, Moderate, High }
private string plantName;
private THREAT plantThreat;
private Texture icon;
}
ポイント
MonoBehaviourじゃなく ScriptableObjectを継承している
クラスに[CreateAssetMenu] attribute がついている
Asset Menu で 右クリック > Create > menuName で Scriptable Object を作れる
fileName: 初期名(C# Script なら NewScript とか)
menuName
order : 既存のContext Menu は 50 番まで埋まってるので、51番から新しいセクションを作れる
[SerializeField]属性がついた、3つのprivateプロパティがある
Serialize フィールド
Serialize = ここでは、JSON文字列などのメタデータに変換してUnity Editor で表示、編集できることを指す
殆どのケースで使用する必要が無いとされている。
なぜなら、public変数にしておけば自動的にEditor の Inspector で編集できるようになるから
(この機能は .NET 特有のシリアライズ機能)
つまり、スクリプト実行環境では編集させないようにして、Unity Editorからだけ操作できるようにしたいという
運用上のニッチなケースでのみ役立つ
C# attribute
Java や python や Dart のデコレータのようなもの
コードに意味を付けて処理する。
Asset Menu に SO を追加
https://gyazo.com/100bf5a26ff8f5b023f949b398537867
選択して、インスペクタから項目を設定できる
名前
アイコン(Texture)
驚異レベル(Enum)
これらの作成した Scriptable Objectを活用するには、これらを参照する Component Script を書く必要がある。
Plant Script
最初はこれだけ
code: Plant.cs
public class Plant : MonoBehaviour
{
private PlantData info;
}
Inspector 上からPlantDataオブジェクトを追加できる。
BoxColider も追加しておく
Prefabを一気にヒエラルキーに追加して、変更してから Apply Allすると楽
(作業場としてヒエラルキーを使う)
Prefab: Apply or Revert
Apply: Clone元のPrefab Asset に変更を反映する(他のCloneにも)
Revert: Clone してあるゲームオブジェクトをprefabの設定値に戻す
UIに情報を表示する
下準備
次のような順序で反映されると思われる
1. PlantコンポーネントがBoxColliderへのクリックを検知
2. PlantにUIのオブジェクトへの参照を持っておく(SetPlantInfoscript component)
3. spi を使ってレンダリング
SetPlantInfoスクリプトを使うため、それがアタッチされたオブジェクトをタグ検索できるように、
タグを付けておく
Inspector > tag > Add Tag > PlantInfo
Plant
code: Plant.cs
using UnityEngine.UI;
public class Plant : MonoBehaviour
{
private PlantData info;
SetPlantInfo setPlantInfo;
private void Start()
{
setPlantInfo = GameObject.FindWithTag("PlantInfo").GetComponent<SetPlantInfo>();
}
private void OnMouseDown()
{
setPlantInfo.OpenPlantPanel();
setPlantInfo.plantName.text = info.Name;
setPlantInfo.threatLevel.text = info.Threat.ToString();
setPlantInfo.plantIcon.GetComponent<RawImage>().texture = info.Icon;
}
public PlantData.THREAT Threat { get { return info.Threat; } }
}
Start()
GameObject.FindWithTag()でUIオブジェクトを探す
GetComponent<SetPlantInfo>()で、植物情報をUIにセットするスクリプトを見つける
OnMouseDown()
Collliderがついてれば、使えるようになるoverride用メソッド
クリックされたらspiに色々セットする。
Threat : 衝突時に相手から読み取らせる用の getter
PlantData
code: PlantData.cs
public class PlantData : ScriptableObject
{
public enum THREAT { None, Low, Moderate, High }
private string plantName;
private THREAT plantThreat;
private Texture icon;
public string Name { get { return plantName; } }
public THREAT Threat { get { return plantThreat; } }
public Texture Icon { get { return icon; } }
}
gettter を設定して、読み取り専用の値を持たせる。
CombatJane の PlayerContoller.cs を編集
ここからはチャレンジ
死ぬアニメーションを再生する処理が FixedUpdate()に含まれているので、
もし PlantData.THREAT.High のScriptable Object を持つ植物に出会ったら、
死亡させる (deat = true)
code: PlayerController.cs
{
...
private void OnCollisionEnter(Collision other)
{
if (other.gameObject.tag == "Plant")
{
Debug.Log("this is plant");
var plant = other.gameObject.GetComponent<Plant>();
Debug.Log(plant.Threat.ToString());
if (plant.Threat == PlantData.THREAT.High)
dead = true;
}
}
}
ここでもTag機能を使う
大文字小文字の判定があるので注意
というか、動画講座では Plant側に相手を死亡させる処理を書いていた。
ソッチのほうが楽かも
Player と 危険物は 1対多
Plant以外にもあるかもしれないので